#include "syntax_parser.h"
#include "errors_warnings.h"

#include "main_container.h"
extern MainContainer * CompilerData;

// get next lexic unit
// returns 'false' if ';' or 'endOfFile' is read
bool Parser::getNextLexicUnit(int *position, LexicUnit * unit)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("getNextLexicUnit");
#endif
	(*position)++;
	(*unit) = CompilerData->Units->GetLexicUnit(*position);
	if ((unit->type == LUTypeSpecialCharacter && unit->subtype == SpecialCharacterSemicolon) ||
			(unit->type == LUTypeSpecialType && unit->subtype == endOfFile) )
		{
			// ERROR has been found
			// REPORT ERROR
			// MAKE LOGICAL RECOVERING
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("getNextLexicUnit");
			#endif
			return false;
		}
	
#ifdef TRACE
      CompilerData->LogTrace->ReportValue("type: ",(*unit).type);
      CompilerData->LogTrace->ReportValue("subtype: ",(*unit).subtype);
	CompilerData->LogTrace->ReportExit("getNextLexicUnit");
#endif
   return true;
}


// get next lexic unit
// returns 'false' if  'endOfFile' is read
bool Parser::getNextLexicUnit2(int *position, LexicUnit * unit)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("getNextLexicUnit2");
#endif
	(*position)++;
	(*unit) = CompilerData->Units->GetLexicUnit(*position);
	if (
			(unit->type == LUTypeSpecialType && unit->subtype == endOfFile) )
		{
			// ERROR has been found
			// REPORT ERROR
			// MAKE LOGICAL RECOVERING
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("getNextLexicUnit");
			#endif
			return false;
		}
	
#ifdef TRACE
      CompilerData->LogTrace->ReportValue("type: ",(*unit).type);
      CompilerData->LogTrace->ReportValue("subtype: ",(*unit).subtype);
	CompilerData->LogTrace->ReportExit("getNextLexicUnit2");
#endif
   return true;
}

// check if we can match <class_definition>  
//<class_definition> -> <class_mods> <template_definition> class NAME <class_inherit> { <using_directives> <class_body> }
//      {abstract, public, private, protected, final, template, class}
bool Parser::isClassProduction(int currentPosition)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("isClassProduction");
#endif
	int position;
	LexicUnit currentUnit;

    // get next lexic unit, if ';' or 'endOfFile' return 0
	position = currentPosition-1;
	if (!getNextLexicUnit(&position, &currentUnit)) 
   {
#ifdef TRACE
         CompilerData->LogTrace->ReportLine("Wrong terminal symbol found, ending method");
			CompilerData->LogTrace->ReportExit("isClassProduction");
#endif
			return 0;
   }
	// jump over <class_mods>
	while (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordAbstract ||
			currentUnit.subtype == KeywordPublic ||	currentUnit.subtype == KeywordPrivate ||
			currentUnit.subtype == KeywordProtected || currentUnit.subtype == KeywordFinal))
	{ 
#ifdef TRACE
         CompilerData->LogTrace->ReportLine("class mode recognized");
#endif
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit)) 
      {
         #ifdef TRACE
					CompilerData->LogTrace->ReportExit("isClassProduction");
			#endif
			return 0;
      }
	}	

    if (currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordTemplate)
	{

         #ifdef TRACE
      CompilerData->LogTrace->ReportLine("keyword template found");
			#endif
		do
		{
			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isClassProduction");
				#endif
				return 0;
			}
		} while (currentUnit.type != LUTypeOperator || currentUnit.subtype != OperatorGreaterThan );
      
      	// get next lexic unit, if ';' or 'endOfFile' return 0
	      if (!getNextLexicUnit(&position, &currentUnit))
	      {
		      #ifdef TRACE
			      CompilerData->LogTrace->ReportExit("isClassProduction");
		      #endif
		      return 0;
	      }
	}


	// check for 'class'
	if (currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordClass)
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isClassProduction");
		#endif
		return 1;
	}
 #ifdef TRACE
	CompilerData->LogTrace->ReportExit("isClassProduction");
#endif
	return 0;

}

// check if we can match <method_definition>
//<method_definition> -> <method_mods> <start_process> <data_type> NAME ( <arguments> ) <method_body_decl> 
//      {abstract, virtual, public, private, protected, override, static, final, start, process, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME}
//<method_definition> -> <method_mods> numeric <numeric_mod> <data_type> NAME ( <arguments> ) { <inf_begin> <value_pairs> <inf_end> } 
//      {abstract, virtual, public, private, protected, override, static, final, numeric} 
bool Parser::isMethodProduction(int currentPosition)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("isMethodProduction");
#endif
	int position;
	LexicUnit currentUnit;

	// get next lexic unit, if ';' or 'endOfFile' return 0
	position = currentPosition-1;
	if (!getNextLexicUnit(&position, &currentUnit))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isMethodProduction");
		#endif
		return 0;
	}
	// jump over <method_mods>
	while (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordAbstract ||
			currentUnit.subtype == KeywordVirtual || currentUnit.subtype == KeywordPublic ||
			currentUnit.subtype == KeywordPrivate || currentUnit.subtype == KeywordProtected ||
			currentUnit.subtype == KeywordOverride || currentUnit.subtype == KeywordStatic ||
			currentUnit.subtype == KeywordFinal))
	{ 
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isMethodProduction");
			#endif
			return 0;
		}
	}	

	// check for 'start' or 'process' or 'numeric'
	if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordStart ||
		currentUnit.subtype == KeywordProcess || currentUnit.subtype == KeywordNumeric))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isMethodProduction");
		#endif
		return 1;
	}
	// jump over <data_type>
	if (currentUnit.type == LUTypeIdentifier)
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isMethodProduction");
			#endif
			return 0;
		}
		// jump over <name>
		while (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterPeriod)
		{
			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isMethodProduction");
				#endif
				return 0;
			}

			if (currentUnit.type != LUTypeIdentifier)
				{ 
					// error
					#ifdef TRACE
						CompilerData->LogTrace->ReportExit("isMethodProduction");
					#endif
					return 0;
				}

			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isMethodProduction");
				#endif
				return 0;
			}
		}
		// jump over <template_use>
		if (currentUnit.type == LUTypeOperator && currentUnit.subtype == OperatorLessThan)
		{
			// jump to first lexic unit after'>'
			do 
			{
				// get next lexic unit, if ';' or 'endOfFile' return 0
				if (!getNextLexicUnit(&position, &currentUnit))
				{
					#ifdef TRACE
						CompilerData->LogTrace->ReportExit("isMethodProduction");
					#endif
					return 0;
				}
			} while (currentUnit.type != LUTypeOperator || currentUnit.subtype != OperatorGreaterThan);
			
			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isMethodProduction");
				#endif
				return 0;
			}
		}
	} 
	else if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
			 currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
			 currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
			 currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
			 currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
			 currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
			 currentUnit.subtype == KeywordOutputStream) )
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isMethodProduction");
			#endif
			return 0;
		}
	}
	// jump over NAME

	if (currentUnit.type != LUTypeIdentifier)
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isMethodProduction");
		#endif
		return 0;
	}
	// get next lexic unit, if ';' or 'endOfFile' return 0
	if (!getNextLexicUnit(&position, &currentUnit))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isMethodProduction");
		#endif
		return 0;
	}
	//  check for special character '('
	if (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterLeftParenthesis)
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isMethodProduction");
		#endif
		return 1;
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("isMethodProduction");
#endif
return 0;

}

// check if we can match <field_definition>
//<field_definition> -> <field_mods> <data_type> <field_names> ; 
//      {trace, const, public, private, protected, static, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME}  
bool Parser::isFieldProduction(int currentPosition)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("isFieldProduction");
#endif
	int position;
	LexicUnit currentUnit;

	// get current lexic unit
	position = currentPosition-1;
	if (!getNextLexicUnit(&position, &currentUnit))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isFieldProduction");

		#endif
		return 0;
	}
	// jump over <field_mods>
	while (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordConst ||
			currentUnit.subtype == KeywordPublic || currentUnit.subtype == KeywordPrivate ||
			currentUnit.subtype == KeywordProtected || currentUnit.subtype == KeywordStatic))
	{ 
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isFieldProduction");
			#endif
			return 0;
		}
	}	
	
	if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype ==KeywordTrace))
	{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isFieldProduction");
			#endif
			return 1;
	}

	// jump over <data_type>
	if (currentUnit.type == LUTypeIdentifier)
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isFieldProduction");
			#endif
			return 0;
		}
		// jump over <name>
		while (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterPeriod)
		{
			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isFieldProduction");
				#endif
				return 0;
			}
			if (currentUnit.type != LUTypeIdentifier)
				{ 
					// error
					#ifdef TRACE
						CompilerData->LogTrace->ReportExit("isFieldProduction");
					#endif
					return 0;
				}

			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isFieldProduction");
				#endif
				return 0;
			}
		}
		// jump over <template_use>
		if (currentUnit.type == LUTypeOperator && currentUnit.subtype == OperatorLessThan)
		{
			// jump to first lexic unit after'>'
			do 
			{
				// get next lexic unit, if ';' or 'endOfFile' return 0
				if (!getNextLexicUnit(&position, &currentUnit))
				{
					#ifdef TRACE
						CompilerData->LogTrace->ReportExit("isFieldProduction");
					#endif
					return 0;
				}
			} while (currentUnit.type != LUTypeOperator || currentUnit.subtype != OperatorGreaterThan);
			
			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit)) 
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isFieldProduction");
				#endif
				return 0;
			}
		}
	} 
	else if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
			 currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
			 currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
			 currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
			 currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
			 currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
			 currentUnit.subtype == KeywordOutputStream) )
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isFieldProduction");
			#endif
			return 0;
		}
	}


	// jump over NAME
	if (currentUnit.type != LUTypeIdentifier)
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isFieldProduction");
		#endif
		return 0;
	}
	// get next lexic unit, if ';' or 'endOfFile' return 0
	if (!getNextLexicUnit2(&position, &currentUnit))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isFieldProduction");
		#endif
		return 0;
	}

	// check for  '[ ]', '=' , ',' , ';' 
	if (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterLeftSquareBracket)
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isFieldProduction");
			#endif
			return 0;
		}
		if (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterRightSquareBracket)
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isFieldProduction");
			#endif
			return 1;
		}
	} 
	else if ((currentUnit.type == LUTypeOperator && currentUnit.subtype == OperatorAssigment) ||
			(currentUnit.type == LUTypeSpecialCharacter && 
			(currentUnit.subtype == SpecialCharacterComma || currentUnit.subtype == SpecialCharacterSemicolon)))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isFieldProduction");
		#endif
		return 1;
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("isFieldProduction");
#endif
	return 0;
}

// check if we can match <property_definition>
//<property_definition> -> <property_mods> <data_type> <property_name>
//      {public, protected, private, static, abstract, override, virtual, final, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME}  
bool Parser::isPropertyProduction(int currentPosition)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("isPropertyProduction");
#endif
	int position;
	LexicUnit currentUnit;

	// get current lexic unit
	position = currentPosition-1;
	if (!getNextLexicUnit(&position, &currentUnit))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isPropertyProduction");
		#endif
		return 0;
	}
	// jump over <property_mods>
	while (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordPublic ||
			currentUnit.subtype == KeywordProtected || currentUnit.subtype == KeywordPrivate ||
			currentUnit.subtype == KeywordStatic || currentUnit.subtype == KeywordAbstract ||
			currentUnit.subtype == KeywordOverride || currentUnit.subtype == KeywordVirtual ||
			currentUnit.subtype == KeywordFinal))
	{ 
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isPropertyProduction");
			#endif
			return 0;
		}
	}	

	// jump over <data_type>
	if (currentUnit.type == LUTypeIdentifier)
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isPropertyProduction");
			#endif
			return 0;
		}
		// jump over <name>
		while (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterPeriod)
		{
			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isPropertyProduction");
				#endif
				return 0;
			}
			if (currentUnit.type != LUTypeIdentifier)
				{ 
					// error
					#ifdef TRACE
						CompilerData->LogTrace->ReportExit("isPropertyProduction");
					#endif
					return 0;
				}

			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isPropertyProduction");
				#endif
				return 0;
			}
		}
		// jump over <template_use>
		if (currentUnit.type == LUTypeOperator && currentUnit.subtype == OperatorLessThan)
		{
			// jump to first lexic unit after'>'
			do 
			{
				// get next lexic unit, if ';' or 'endOfFile' return 0
				if (!getNextLexicUnit(&position, &currentUnit))
				{
					#ifdef TRACE
						CompilerData->LogTrace->ReportExit("isPropertyProduction");
					#endif
					return 0;
				}
			} while (currentUnit.type != LUTypeOperator || currentUnit.subtype != OperatorGreaterThan);
			
			// get next lexic unit, if ';' or 'endOfFile' return 0
			if (!getNextLexicUnit(&position, &currentUnit))
			{
				#ifdef TRACE
					CompilerData->LogTrace->ReportExit("isPropertyProduction");
				#endif
				return 0;
			}
		}
	} 
	else if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
			 currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
			 currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
			 currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
			 currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
			 currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
			 currentUnit.subtype == KeywordOutputStream) )
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit))
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isPropertyProduction");
			#endif
			return 0;
		}
	}


	// jump over NAME
	if (currentUnit.type != LUTypeIdentifier)
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isPropertyProduction");
		#endif
		return 0;
	}
	// get next lexic unit, if ';' or 'endOfFile' return 0
	if (!getNextLexicUnit(&position, &currentUnit))
	{
		#ifdef TRACE
			CompilerData->LogTrace->ReportExit("isPropertyProduction");
		#endif
		return 0;
	}

	// check for  '[ int', '{'  
	if (currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterLeftSquareBracket)
	{
		// get next lexic unit, if ';' or 'endOfFile' return 0
		if (!getNextLexicUnit(&position, &currentUnit)) 
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isPropertyProduction");
			#endif
			return 0;
		}
		if (currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordInt)
		{
			#ifdef TRACE
				CompilerData->LogTrace->ReportExit("isPropertyProduction");
			#endif
			return 1;
		}
	} 
	else if ((currentUnit.type == LUTypeSpecialCharacter && currentUnit.subtype == SpecialCharacterLeftCurlyBrace) )
	{
		#ifdef TRACE
		CompilerData->LogTrace->ReportExit("isPropertyProduction");
		#endif
		return 1;
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("isPropertyProduction");
#endif
	return 0;
}


// <main_definition> ~ <namespace_definition>  {namespace}
// <main_definition> ~ <enum_definition>  {enum}
// <main_definition> ~ <class_definition>  {class, template, abstract, public, private, protected, final}
// <main_definition> ~ <model_definition>  {model, public, private}
// <main_definition> ~ <method_definition>  {numeric, start, process, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, abstract, virtual, public, private, protected, override, static, final}
// <main_definition> ~ <field_definition>  {trace, int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, const, public, private, protected, static}
// <main_definition> ~ <property_definition>  {int, float, bool, state, time, void, Facility, Storage, Queue, ADTable, Group, OutputStream, NAME, public, protected, private, static, abstract, override, virtual, final}
void Parser::Parse_MainDefinition(SyntaxTreeNode * parent)
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("Parse_MainDefinition");
#endif
	LexicUnit currentUnit, nextUnit;
	// get current lexic unit
#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Getting lexic unit.");
#endif
	currentUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition);
	nextUnit = CompilerData->Units->GetLexicUnit(this->CurrentLexicPosition + 1);

	if( currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordNamespace )
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__NamespaceDefinition;

		// process nonterminal symbol <namespace_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_NamespaceDefinition(newNode0);

	}

	else if (currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordEnum)
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__EnumDefinition;

		// process nonterminal symbol <enum_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_EnumDefinition(newNode0);
	}

	else if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordClass ||
			 currentUnit.subtype == KeywordTemplate ))
	{		
		// write type of production in this node
		parent->Production = Gr_MainDefinition__ClassDefinition;

		// process nonterminal symbol <class_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_ClassDefinition(newNode0);
	}
	
	else if(currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordNumeric ||
			currentUnit.subtype == KeywordStart || currentUnit.subtype == KeywordProcess))
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__MethodDefinition;

		// process nonterminal symbol <method_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_MethodDefinition(newNode0);
	}

	else if((currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordModel) ||
			((currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordPublic) ||
			(currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordPrivate)) &&
			(nextUnit.type == LUTypeKeyword && nextUnit.subtype == KeywordModel) )
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__ModelDefinition;

		// process nonterminal symbol <model_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_ModelDefinition(newNode0);
	}

	else if (currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordConst||currentUnit.subtype ==KeywordTrace ))
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__FieldDefinition;

		// process nonterminal symbol <field_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_FieldDefinition(newNode0);
	}

	else if	(((currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordAbstract) ||
			(currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordPublic) ||
			(currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordPrivate) ||
			(currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordProtected)||
         (currentUnit.type == LUTypeKeyword && currentUnit.subtype == KeywordFinal)) 
			&& isClassProduction (this->CurrentLexicPosition) )
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__ClassDefinition;

		// process nonterminal symbol <class_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_ClassDefinition(newNode0);
	}

	else if(((currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
			currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
			currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
			currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
			currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
			currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
			currentUnit.subtype == KeywordOutputStream || currentUnit.subtype == KeywordAbstract ||
			currentUnit.subtype == KeywordVirtual || currentUnit.subtype == KeywordPublic ||
			currentUnit.subtype == KeywordPrivate || currentUnit.subtype == KeywordProtected ||
			currentUnit.subtype == KeywordOverride || currentUnit.subtype == KeywordStatic ||
			currentUnit.subtype == KeywordFinal)) ||
			currentUnit.type == LUTypeIdentifier)
			&& isMethodProduction (this->CurrentLexicPosition))
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__MethodDefinition;

		// process nonterminal symbol <method_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_MethodDefinition(newNode0);
	}

	else if(((currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
			currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
			currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
			currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
			currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
			currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
			currentUnit.subtype == KeywordOutputStream || currentUnit.subtype == KeywordPublic ||
			currentUnit.subtype == KeywordPrivate || currentUnit.subtype == KeywordProtected ||
			currentUnit.subtype == KeywordStatic)) ||
			currentUnit.type == LUTypeIdentifier )
			&& isFieldProduction (this->CurrentLexicPosition) )
	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__FieldDefinition;

		// process nonterminal symbol <field_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_FieldDefinition(newNode0);
	}

	else if(((currentUnit.type == LUTypeKeyword && (currentUnit.subtype == KeywordInt ||
			currentUnit.subtype == KeywordFloat || currentUnit.subtype == KeywordBool ||
			currentUnit.subtype == KeywordState || currentUnit.subtype == KeywordTime ||
			currentUnit.subtype == KeywordVoid || currentUnit.subtype == KeywordFacility ||
			currentUnit.subtype == KeywordStorage || currentUnit.subtype == KeywordQueue ||
			currentUnit.subtype == KeywordADTable || currentUnit.subtype == KeywordGroup ||
			currentUnit.subtype == KeywordOutputStream || currentUnit.subtype == KeywordPublic ||
			currentUnit.subtype == KeywordProtected || currentUnit.subtype == KeywordPrivate ||
			currentUnit.subtype == KeywordStatic || currentUnit.subtype == KeywordAbstract ||
			currentUnit.subtype == KeywordOverride || currentUnit.subtype == KeywordVirtual ||
			currentUnit.subtype == KeywordFinal)) ||
			currentUnit.type == LUTypeIdentifier)
			&& isPropertyProduction (this->CurrentLexicPosition) )

	{
		// write type of production in this node
		parent->Production = Gr_MainDefinition__PropertyDefinition;

		// process nonterminal symbol <property_definition> 
		SyntaxTreeNode * newNode0 = new SyntaxTreeNode();
		parent->Nodes->Add(newNode0);
		Parse_PropertyDefinition(newNode0);

	}


	else
	{
		// ERROR has been found
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&currentUnit, ERR_SYN_NO_MAIN_DEFINITION_BEGINING);
		// This is recovoring from error
        this->CurrentLexicPosition++;
	}
#ifdef TRACE
	CompilerData->LogTrace->ReportExit("Parse_MainDefinition");
#endif
}